﻿using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RainEngine.Rendering;
using RainEngine.SceneNodes;
using RainEngine.SceneNodes.UI;

namespace RainEngine.SceneManagement
{
    /// <summary>
    /// 表示屏幕所处状态的枚举
    /// </summary>
    public enum ScreenState
    {
        TransitionOn,
        Active,
        TransitionOff,
        Hidden,
    }    

    /// <summary>
    /// 这是SceneNode的数据包含容器。一个Scene是根据绘制顺序分组的对象的集合
    /// Scene对象是自我包含的，这样属于这个场景的SceneNodes不会和其他场景中的nodes发生交互
    /// 一个游戏可以包含一个或多个scene，但只有一个是激活的，只绘制属于它的nodes。 
    /// </summary>
    public class Scene
    {
        #region 成员变量和构造函数

        protected RainGE engine;

        protected GraphicsDevice graphicsDevice;

        /// <summary>
        /// 存储这个场景中的SceneNode的集合
        /// </summary>
        List<SceneNode> nodes;

        /// <summary>
        /// 存储这个场景中的Renderable2DSceneNode的集合，即Sprite的集合
        /// </summary>
        List<Renderable2DSceneNode> sprites=new List<Renderable2DSceneNode>();

        /// <summary>
        /// 获取当前场景中的SceneNode的集合
        /// </summary>
        public List<SceneNode> Nodes
        {
            get { return nodes; }
        }        

        /// <summary>
        /// 场景管理器
        /// </summary>
        SceneManager sceneManager;

        /// <summary>
        /// 这个场景拥有的UI管理器
        /// </summary>
        UIManager uiManager;

        /// <summary>
        /// 绘制粒子系统的管理器
        /// </summary>
        Particle2DManager particle2DManager;  
        Particle3DManager particle3DManager;

        /// <summary>
        /// 绘制3D线段的管理器
        /// </summary>
        ShapeManager shapeManager;        
        
        /// <summary>
        /// 处理后期效果的类
        /// </summary>
        PostProcessor postProcessor;

        /// <summary>
        /// 存储后期效果名称的集合
        /// </summary>
        List<string> ppEffectsList = new List<string>(); 
       
        /// <summary>
        /// 后期处理使用的两个渲染目标。
        /// </summary>
        public static RenderTarget2D postProcessorRT1;
        public static RenderTarget2D postProcessorRT2;

        /// <summary>
        /// 是否使用后期处理
        /// </summary>
        bool postProcessEnabled = false;

        /// <summary>
        /// scene的ID
        /// </summary>
        internal int sceneId;

        /// <summary>
        /// scene的名称
        /// </summary>
        private string name;

        /// <summary>
        /// 是否弹出窗口
        /// </summary>
        bool isPopup = false;

        /// <summary>
        /// 是否正在退出
        /// </summary>
        bool isExiting = false;

        /// <summary>
        /// 其他屏幕是否处在激活状态
        /// </summary>
        bool otherScreenHasFocus;

        /// <summary>
        /// 淡入持续的时间
        /// </summary>
        TimeSpan transitionOnTime = TimeSpan.Zero;

        /// <summary>
        /// 淡出持续的时间
        /// </summary>
        TimeSpan transitionOffTime = TimeSpan.Zero;

        /// <summary>
        /// 淡入淡入过程中所处的位置
        /// </summary>
        float transitionPosition = 1;

        //屏幕刚创建时处于淡入状态
        ScreenState screenState = ScreenState.TransitionOn;

        /// <summary>
        /// 是否已经初始化
        /// </summary>
        private bool isInitialized;

        // 需要更新/绘制的节点索引集合
        private IndexList updateList = new IndexList();
        private IndexList renderList = new IndexList();

        /// <summary>
        /// 用于剔除计算的信息，从相机获取
        /// </summary>
        private CullingInfo cullInfo = new CullingInfo();

        /// <summary>
        /// 统计此场景中的节点信息
        /// </summary>
        internal RenderStatistics lastStat, currentStat;

        private bool isFrameRendered = true;

        /// <summary>
        /// 场景的环境光颜色。
        /// </summary>
        //private Vector3 ambientLightColor = new Vector3(0.05333332f, 0.09882354f, 0.1819608f);
        private Vector3 ambientLightColor = new Vector3(0.05f, 0.05f, 0.05f);

        /// <summary>
        /// 光源数组
        /// </summary>           
        public Light[] lights;

        /// <summary>
        /// 场景的雾化颜色，默认为白色
        /// </summary>
        private Vector3 fogColor = Vector3.One;

        /// <summary>
        /// 场景的雾化开始距离
        /// </summary>
        private float fogStart = 50.0f;

        /// <summary>
        /// 场景的雾化结束距离
        /// </summary>
        private float fogEnd = 100.0f;

        /// <summary>
        /// 场景中相机的相关属性
        /// </summary>
        Matrix viewMatrix = Matrix.Identity;
        internal Matrix reflectionViewMatrix= Matrix.Identity;
        Matrix projectionMatrix = Matrix.Identity;
        Vector3 camPositon = Vector3.Zero;
        
        /// <summary>
        /// 是否实现折射，默认为false
        /// </summary>
        private bool refractEnabled = false;

        /// <summary>
        /// 用于折射的渲染目标
        /// </summary>
        internal RenderTarget2D RefractionRenderTarget;

        /// <summary>
        /// 是否实现反射，默认为false
        /// </summary>
        private bool reflectEnabled = false;

        /// <summary>
        /// 用于反射的渲染目标
        /// </summary>
        internal RenderTarget2D ReflectionRenderTarget;
        
        /// <summary>
        /// 场景中的水面高度，默认为0
        /// </summary>
        internal float WaterHeight = 0f;

        /// <summary>
        /// 不允许不带参数的构造函数
        /// </summary>
        private Scene() { }
        
        /// <summary>
        /// 创建一个新scene对象
        /// </summary>
        /// <param name="engine">引擎</param>
        /// <param name="name">scene的名称</param>
        public Scene(RainGE engine, string name) : this(engine, 0, name) { }

        /// <summary>
        /// 创建一个Scene
        /// </summary>
        /// <param name="engine">引擎</param>
        /// <param name="name">scene的名称</param>
        /// <param name="aproxNodes">初始化nodes集合</param>
        public Scene(RainGE engine, string name, int aproxNodes) : this(engine, 0, name, aproxNodes) { }
        
        /// <summary>
        /// 给定ID创建一个新Scene对象。
        /// 调用者必须保证ID唯一
        /// </summary>
        /// <param name="engine">引擎</param>
        /// <param name="sceneId">ID</param>
        /// <param name="name">名称</param>
        internal Scene(RainGE engine, ushort sceneId, string name) : this(engine, sceneId, name, 255) { }

        /// <summary>
        /// 使用一个给定ID创建一个Scene。
        /// 调用者必须保证ID唯一
        /// </summary>
        /// <param name="engine">引擎</param>
        /// <param name="sceneId">ID</param>
        /// <param name="name">名称</param>
        /// <param name="aproximateNodes">估计的节点数量</param>
        internal Scene(RainGE engine, ushort sceneId, string name, int aproximateNodes)
        {
            this.sceneId = sceneId;
            this.name = name;
            this.engine = engine;
            this.graphicsDevice = engine.GraphicsDevice;
            this.sceneManager = engine.SceneManager;

            // 默认不显示光标
            this.IsShowMouse = false;

            uiManager = new UIManager(engine, this);
            particle2DManager = new Particle2DManager(engine, this);
            particle3DManager = new Particle3DManager();
            shapeManager = new ShapeManager(engine.GraphicsDevice);

            //renderCapture = new RenderCapture(engine.GraphicsDevice);
            postProcessor = new PostProcessor(graphicsDevice);
            SetupPPRenderTarget2D();
            graphicsDevice.DeviceReset += new EventHandler<EventArgs>(graphicsDevice_DeviceReset);


            this.nodes = new List<SceneNode>(aproximateNodes);

            lights = new Light[3];
            SetupLights();
            SetupCamera();
        }

        /// <summary>
        /// 创建默认光源
        /// </summary>
        private void SetupLights()
        {
            // 主光源，淡黄色。
            lights[0] = new Light(new Vector3(1, 0.9607844f, 0.8078432f), new Vector3(-0.5265408f, -0.5735765f, -0.6275069f));
            lights[0].LightPropertyChanged += new RainEngine.Rendering.Light.LightPropertyChangedEventHandler(Scene_LightPropertyChanged);
 
            // Fill light.暗黄色
            lights[1] = new Light(new Vector3(0.9647059f, 0.7607844f, 0.4078432f), new Vector3(0.7198464f, 0.3420201f, 0.6040227f));
            lights [1].LightPropertyChanged +=new Light.LightPropertyChangedEventHandler(Scene_LightPropertyChanged);

            // Back light.灰色
            lights[2] = new Light(new Vector3(0.3231373f, 0.3607844f, 0.3937255f), new Vector3(0.4545195f, -0.7660444f, 0.4545195f));
            lights [2].LightPropertyChanged +=new Light.LightPropertyChangedEventHandler(Scene_LightPropertyChanged);
        }

        /// <summary>
        /// 当光源属性发生变化时的处理程序
        /// </summary>
        void Scene_LightPropertyChanged(object sender, LightPropertyChangedEventArgs e)
        {
            int lightIndex = 0;
            for (int i = 0; i < lights.Length; i++)
            {
                if ((Light)sender == lights[i])
                {
                    lightIndex = i;
                    break;
                }
            }
            
            if (e.LightProperty == "Enabled")
            {
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i] is ISceneNodeLighting)
                        ((ISceneNodeLighting)nodes[i]).SetLightEnabled (lightIndex, lights[lightIndex].Enabled);
                }
            }
            else if (e.LightProperty == "LightType")
            {
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i] is ISceneNodeLighting)
                        ((ISceneNodeLighting)nodes[i]).SetLightType (lightIndex,(float)lights[lightIndex].LightType);
                }
            }
            else if (e.LightProperty == "Color")
            {
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i] is ISceneNodeLighting)
                        ((ISceneNodeLighting)nodes[i]).SetLightVector3 (lightIndex,"color",lights[lightIndex].Color);
                }
            }
            else if (e.LightProperty == "Direction")
            {
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i] is ISceneNodeLighting)
                        ((ISceneNodeLighting)nodes[i]).SetLightVector3(lightIndex, "direction", lights[lightIndex].Direction );
                }
            }
            else if (e.LightProperty == "Position")
            {
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i] is ISceneNodeLighting)
                        ((ISceneNodeLighting)nodes[i]).SetLightVector3(lightIndex, "position", lights[lightIndex].Position);
                }
            }
            else if (e.LightProperty == "SpotData")
            {
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i] is ISceneNodeLighting)
                        ((ISceneNodeLighting)nodes[i]).SetLightSpotData (lightIndex, lights[lightIndex].SpotData);
                }
            }
        }        

        /// <summary>
        /// 创建默认相机
        /// </summary>
        private void SetupCamera()
        {
            this.Camera = new CameraSceneNode(graphicsDevice, this, Vector3.Zero, Vector3.Forward);
            Camera.Initialize();
        }

        void graphicsDevice_DeviceReset(object sender, EventArgs e)
        {
            SetupPPRenderTarget2D();
        }

        /// <summary>
        /// 创建后期处理使用的两个渲染目标
        /// </summary>
        private void SetupPPRenderTarget2D()
        {
            postProcessorRT1 = new RenderTarget2D(graphicsDevice, graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, false, SurfaceFormat.Color, DepthFormat.Depth24);
            postProcessorRT2 = new RenderTarget2D(graphicsDevice, graphicsDevice.Viewport.Width, graphicsDevice.Viewport.Height, false, SurfaceFormat.Color, DepthFormat.Depth24);
        }


        #endregion

        #region 属性

        /// <summary>
        /// 获取这个场景拥有的uiManager
        /// </summary>
        public UIManager UiManager
        {
            get { return uiManager; }
        }

        /// <summary>
        /// 获取这个屏幕所属的场景管理器
        /// </summary>
        public SceneManager SceneManager
        {
            get { return sceneManager; }
            internal set { sceneManager = value; }
        }

        /// <summary>
        /// 检查当前屏幕是否被激活可以接受用户输入。
        /// </summary>
        public bool IsActive
        {
            get
            {
                return !otherScreenHasFocus &&
                       (screenState == ScreenState.TransitionOn ||
                        screenState == ScreenState.Active);
            }
        }

        /// <summary>
        /// 返回scene中的node数量
        /// </summary>
        public int NodesCount { get { return nodes.Count; } }

        /// <summary>
        /// 获取当前屏幕变换的位置，从0(完全激活，没有转换)到1(转换到完全没有)。
        /// </summary>
        public float TransitionPosition
        {
            get { return transitionPosition; }
            protected set { transitionPosition = value; }
        }

        /// <summary>
        /// 返回scene的ID.
        /// </summary>
        public int ID { get { return sceneId; } }

        /// <summary>
        /// 当一个屏幕在另一个之上时，第一个屏幕会淡出给新的屏幕留出位置
        /// 这个属性表示这个屏幕是否是一个弹出屏幕
        /// </summary>
        public bool IsPopup
        {
            get { return isPopup; }
            protected set { isPopup = value; }
        }

        /// <summary>
        /// 获取或设置是否显示光标
        /// </summary>
        public bool IsShowMouse { get; set; }

        /// <summary>
        /// 返回scene的名称
        /// </summary>
        public string Name { get { return name; } }

        /// <summary>
        /// 有两个原因屏幕会淡出。
        /// 有可能它暂时离开为另一个屏幕留出位置，或者就是退出。
        /// 这个属性表示屏幕是否在退出：
        /// 如果是，屏幕会在淡出结束后移除自己。
        /// </summary>
        public bool IsExiting
        {
            get { return isExiting; }
            protected internal set { isExiting = value; }
        }

        /// <summary>
        /// 获取或设置屏幕淡出持续的时间
        /// </summary>
        public TimeSpan TransitionOffTime
        {
            get { return transitionOffTime; }
            protected set { transitionOffTime = value; }
        }

        /// <summary>
        /// 获取当前转换的alpha值，从255 (完全激活，没有转换)到0(转换到完全没有)。
        /// </summary>
        public byte TransitionAlpha
        {
            get { return (byte)(255 - TransitionPosition * 255); }
        }


        /// <summary>
        /// 获取当前屏幕状态。
        /// </summary>
        public ScreenState ScreenState
        {
            get { return screenState; }
            protected set { screenState = value; }
        }

        /// <summary>
        /// 获取或设置屏幕淡入的时间
        /// </summary>
        public TimeSpan TransitionOnTime
        {
            get { return transitionOnTime; }
            set { transitionOnTime = value; }
        }

        /// <summary>
        /// 获取或设置当前相机。
        /// </summary>
        public CameraSceneNode Camera { get; set; }

        /// <summary>
        /// 获取或设置环境光颜色。
        /// </summary>
        public Vector3 AmbientLightColor
        {
            get
            {
                return ambientLightColor;
            }
            set
            {
                ambientLightColor = value;
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i] is ISceneNodeLighting )
                        ((ISceneNodeLighting)nodes[i]).SetAmbientLightColor (ambientLightColor );
                }
            }
        }        

        /// <summary>
        /// 获取或设置雾化颜色。
        /// </summary>
        public Vector3 FogColor
        {
            get { return fogColor; }
            set
            {
                fogColor = value;
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i] is ISceneNodeFog)
                        ((ISceneNodeFog)nodes[i]).SetFogColor(fogColor);
                }
            }
        }

        /// <summary>
        /// 获取或设置雾化开始的距离。
        /// </summary>
        public float FogStart
        {
            get { return fogStart; }
            set
            {
                fogStart = value;
                if (fogStart < 0)
                    fogStart = 0;
                if (fogStart > fogEnd)
                    fogStart = fogEnd;
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i] is ISceneNodeFog)
                        ((ISceneNodeFog)nodes[i]).SetFogStart(fogStart);
                }
            }
        }

        /// <summary>
        /// 获取或设置雾化结束的距离。
        /// </summary>
        public float FogEnd
        {
            get { return fogEnd; }
            set
            {
                fogEnd = value;
                if (fogEnd < 0)
                    fogEnd = 0;
                if (fogStart > fogEnd)
                    fogEnd =fogStart ;
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i] is ISceneNodeFog)
                        ((ISceneNodeFog)nodes[i]).SetFogEnd(fogEnd);
                }
            }
        }

        /// <summary>
        /// 获取或设置是否实现折射
        /// </summary>
        internal  bool RefractEnabled
        {
            get { return refractEnabled; }
            set
            {
                refractEnabled = value;
                if (refractEnabled)
                {
                    //初始化用于水面折射的渲染目标
                    //PresentationParameters pp = engine.GraphicsDevice.PresentationParameters;
                    RefractionRenderTarget = new RenderTarget2D(graphicsDevice, graphicsDevice.Viewport.Width,graphicsDevice.Viewport.Height, false, SurfaceFormat.Color,DepthFormat.Depth24);
                }
                else
                {
                    //refractionMap.Dispose();
                    RefractionRenderTarget.Dispose();
                }
            }
        }

        /// <summary>
        /// 获取折射贴图
        /// </summary>
        //public Texture2D RefractionMap
        //{
        //    get { return //refractionMap; }
        //}

        /// <summary>
        /// 获取或设置是否实现反射
        /// </summary>
        internal bool ReflectEnabled
        {
            get { return reflectEnabled; }
            set
            {
                reflectEnabled = value;
                if (reflectEnabled)
                {
                    //初始化用于水面折射的渲染目标
                    //PresentationParameters pp = engine.GraphicsDevice.PresentationParameters;
                    ReflectionRenderTarget = new RenderTarget2D(graphicsDevice, graphicsDevice.Viewport.Width,graphicsDevice.Viewport.Height, false, SurfaceFormat.Color,DepthFormat.Depth24);
                }
                else
                {
                    //reflectionMap.Dispose();
                    ReflectionRenderTarget.Dispose();
                }
            }
        }

        /// <summary>
        /// 获取反射贴图
        /// </summary>
        //public Texture2D ReflectionMap
        //{
            //get { return reflectionMap; }
        //}
        
        #endregion

        #region 虚拟方法

        public virtual void Initialize()
        {
            if (!isInitialized)
            {
                isInitialized = true;                
                LoadContent();
            }
        }

        /// <summary>
        /// 加载素材
        /// </summary>
        public virtual void LoadContent() {}

        /// <summary>
        /// 清除素材
        /// </summary>
        public virtual void UnloadContent() { }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="gameTime"></param>
        /// <param name="otherScreenHasFocus"></param>
        /// <param name="coveredByOtherScreen"></param>
        public virtual void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
        {
            this.otherScreenHasFocus = otherScreenHasFocus;

            //如果处于Exiting过程中
            if (isExiting)
            {
                // 如果此屏幕已经被移除，则它的状态应为TransitionOff
                screenState = ScreenState.TransitionOff;

                if (!UpdateTransition(gameTime, transitionOffTime, 1))
                {
                    // 当变换结束时，移除此屏幕
                    SceneManager.RemoveScene(this);
                }
            }
            else if (coveredByOtherScreen)
            {
                // 如果这个屏幕被其他屏幕覆盖，它应该处于TransitionOff状态
                if (UpdateTransition(gameTime, transitionOffTime, 1))
                {
                    // 仍处于淡出状态
                    screenState = ScreenState.TransitionOff;
                }
                else
                {
                    // 否则淡出结束
                    screenState = ScreenState.Hidden;
                }
            }
            else
            {
                // 否则此屏幕仍处于淡入过程，结束后才能激活
                if (UpdateTransition(gameTime, transitionOnTime, -1))
                {
                    // 仍处于淡入过程
                    screenState = ScreenState.TransitionOn;
                }
                else
                {
                    // 淡入过程结束!
                    screenState = ScreenState.Active;
                }
            }
            
            // 更新相机
            Camera.Update(gameTime);

            //--------------------------------------
            //  从相机获取剔除所需的信息并建立updateList集合
            //  此处设置isFrameRendered的目的在于防止每次更新都重新创建updateList，在Update()的更新频率比Draw()大（这种情况非常常见）的情况中可以节省时间
            //--------------------------------------
            if (isFrameRendered)
            {
                Camera.GetCulling(cullInfo);
                CullManager.UpdatePhaseCulling(updateList, nodes, cullInfo, ref currentStat);
                currentStat.nodesUpdated = (ushort)updateList.Count;
            }

            //--------------------------------------
            //  更新updateList集合中的节点
            //--------------------------------------
            for (int i = 0; i < updateList.counter; i++)
            {
                nodes[updateList.indices[i]].Update(gameTime);
            }

            // 更新此场景中所有Renderable2DSceneNode类型的SceneNode            
            if (this == sceneManager.ActiveScene)
            {
                for (int i = 0; i<UiManager.UiElements.Count;i++ )
                {
                    UiManager.UiElements[i].Update(gameTime);
                }
                for (int i = 0; i < sprites.Count; i++)
                {
                    sprites[i].Update(gameTime);
                }
            }

            particle2DManager.Update(gameTime);
            particle3DManager.Update(gameTime);

            isFrameRendered = false;
        }

        /// <summary>
        /// 更新屏幕变换位置的辅助类
        /// </summary>
        bool UpdateTransition(GameTime gameTime, TimeSpan time, int direction)
        {
            // 淡入淡出过程持续到的位置
            float transitionDelta;

            if (time == TimeSpan.Zero)
                transitionDelta = 1;
            else
                transitionDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds /
                                          time.TotalMilliseconds);

            // 更新淡入淡出的位置
            transitionPosition += transitionDelta * direction;

            // 是否已经在淡入淡出过程的最后?
            if (((direction < 0) && (transitionPosition <= 0)) ||
                ((direction > 0) && (transitionPosition >= 1)))
            {
                transitionPosition = MathHelper.Clamp(transitionPosition, 0, 1);
                return false;
            }

            // 否则仍处于淡入淡出过程中
            return true;
        }

        /// <summary>
        /// 绘制场景
        /// </summary>
        /// <param name="gameTime"></param>
        public virtual void Draw(GameTime gameTime)
        {
            DrawScene(gameTime);
        }

        public void DrawScene(GameTime gameTime)
        {
            //----------------------------
            //  保存上一帧的统计信息
            //----------------------------
            currentStat.CopyTo(ref lastStat);
            currentStat.Reset();

            // 获取相机信息
            Camera.GetViewProjectionPosition(out viewMatrix, out projectionMatrix, out camPositon);

            // 绘制反射贴图
            if (ReflectEnabled)
            {
                DrawReflectionMap(gameTime,Camera ,projectionMatrix ,camPositon );
            }

            // 绘制折射贴图
            if (RefractEnabled)
            {
                DrawRefractionMap(gameTime,viewMatrix ,projectionMatrix ,camPositon );
            }

            // 开始对场景截屏
            if(postProcessEnabled )
                graphicsDevice.SetRenderTarget(postProcessorRT1);
            
            //graphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, engine.BackGroundColor, 1.0f, 0);
            

            // 首先绘制Renderable2DSceneNode
            RainGE.SpriteBatch.Begin(SpriteSortMode.Immediate, null, null, null, null, null, engine.GlobalTransformation);
            for (int i = 0; i < sprites.Count; i++)
            {
                if(sprites [i].Visible)
                    sprites[i].Draw(gameTime);
            }
            RainGE.SpriteBatch.End();
            
            graphicsDevice.DepthStencilState = DepthStencilState.Default;
            graphicsDevice.BlendState = BlendState.Opaque;
            
            //---------------------------------------
            //  剔除不需要绘制的节点
            //---------------------------------------
            CullManager.DrawPhaseCulling(renderList, nodes, cullInfo, ref currentStat);

            // 绘制Renderable3DSceneNode
            for (int i = 0; i < renderList.Count; i++)
            {
                Renderable3DSceneNode rsn = (Renderable3DSceneNode)nodes[renderList[i]];
                currentStat.trisRendered += (uint)rsn.Draw(gameTime, viewMatrix, projectionMatrix, camPositon);
            }
            
            // 绘制线段
            shapeManager.Draw(gameTime,viewMatrix ,projectionMatrix );
            // 绘制粒子
            particle2DManager.Draw(gameTime);
            particle3DManager.Draw(gameTime, viewMatrix, projectionMatrix);
            
            // 结束对场景的截屏            
            if (postProcessEnabled)
            {
                graphicsDevice.SetRenderTarget(null);
                postProcessor.Draw(ppEffectsList, postProcessorRT1,postProcessorRT2);
            }

            // 绘制所有UISceneNode类型的节点
            currentStat.uiNodesRendered += (ushort)uiManager.Draw(gameTime);

            //  将isFrameRendered设置为true，这样Update()就可以知道绘制已经结束，可以更新updateList了
            isFrameRendered = true;
        }

        #endregion

        #region 公有方法        
        
        /// <summary>
        /// 让屏幕可以接受用户输入。不同于Update，这个方法只在激活的屏幕中调用。
        /// </summary>
        public virtual void HandleInput() { }
        
        /// <summary>
        /// 根据node的UpdateOrder属性进行排序
        /// </summary>
        public void UpdateOrder()
        {
            nodes.Sort(updateOrderComparer);
        }

        /// <summary>
        /// 告知屏幕离开，不同于SceneManager.RemoveScene方法，SceneManager.RemoveScene方法会立即移除屏幕
        /// 这个方法让屏幕根据TransitionOffTime逐渐透明化的离开
        /// </summary>
        public void ExitScreen()
        {
            if (TransitionOffTime == TimeSpan.Zero)
            {
                // 如果TransitionOffTime为0，则移除这个屏幕
                SceneManager.RemoveScene(this);
            }
            else
            {
                // 否则仍处于淡出状态，当淡出结束后才能移除这个屏幕
                isExiting = true;
            }
        }

        /// <summary>
        /// 在scene添加一个新node
        /// </summary> 
        /// <param name="newNode">要添加的节点</param>
        /// <returns>若添加成功则返回true</returns>
        public bool AddNode(SceneNode newNode)
        {
            if (engine.GraphicsDevice.IsDisposed)
                return false;

            if (newNode is CameraSceneNode)
                throw new System.InvalidOperationException("不能在场景中添加CameraSceneNode！"); 

            
            newNode.Scene = this;
            if (newNode is UISceneNode)
            {
                UISceneNode element = (UISceneNode)newNode;
                element.UIManager = this.uiManager;
                element.Initialize();
                uiManager.AddElement(element);
                return true;
            }
            else if(newNode is Renderable2DSceneNode )
            {
                newNode .Initialize();
                sprites .Add ((Renderable2DSceneNode)newNode );
                return true;
            }
            else
            {
                newNode.Initialize();
                int idx = FindIndexByOrder(newNode.UpdateOrder);
                nodes.Insert(idx, newNode);
                return true;
            }
        }        

        /// <summary>
        /// Iterates the nodes List and searches the index of the first SceneNode with update order equal or less than the searched nodeOrder.
        /// </summary>
        /// <param name="nodeOrder"></param>
        /// <returns></returns>
        private int FindIndexByOrder(int nodeOrder)
        {
            int lastIndex = -1;
            for (int i = 0; i < nodes.Count; i++)
            {
                if (nodes[i].UpdateOrder >= nodeOrder)
                {
                    lastIndex = i;
                    break;
                }
            }

            if (lastIndex < 0)
                lastIndex = nodes.Count;

            return lastIndex;
        }

        /// <summary>
        /// 从场景中移除一个node
        /// </summary>
        /// <param name="node"></param>
        public void RemoveNode(SceneNode node)
        {
            nodes.Remove(node);
            ChangeUpdateOrder(node);
        }

        /// <summary>
        /// 添加粒子系统
        /// </summary>
        /// <param name="ps">2D粒子系统</param>
        public void AddParticleSystem(Particle2DSystem ps)
        {
            particle2DManager.AddParticle2DSystem(ps);
        }

        /// <summary>
        /// 添加粒子系统
        /// </summary>
        /// <param name="ps">3D粒子系统</param>
        public void AddParticleSystem(Particle3DSystem ps)
        {
            particle3DManager.AddParticle3DSystem(ps);
        }

        /// <summary>
        /// 添加一条直线，只持续一帧。
        /// </summary>
        /// <param name="start">直线的起点坐标。</param>
        /// <param name="end">直线的终点坐标。</param>
        /// <param name="color">直线颜色。</param>
        public void AddLine(Vector3 start, Vector3 end, Color color)
        {
            AddLine(start, end, color,0f);
        }

        /// <summary>
        /// 添加一条直线并设置持续时间。
        /// </summary>
        /// <param name="start">直线的起点坐标。</param>
        /// <param name="end">直线的终点坐标。</param>
        /// <param name="color">直线颜色。</param>
        /// <param name="life">以秒为单位的持续时间。</param>
        public void AddLine(Vector3 start, Vector3 end, Color color, float life)
        {
            shapeManager.AddLine(start, end, color,life);
        }

        /// <summary>
        /// 添加一个三角形，只持续一帧。
        /// </summary>
        /// <param name="a">三角形的第一个顶点坐标。</param>
        /// <param name="b">三角形的第二个顶点坐标。</param>
        /// <param name="c">三角形的第三个顶点坐标。</param>
        /// <param name="color">线条颜色。</param>
        public void AddTriangle(Vector3 a, Vector3 b, Vector3 c, Color color)
        {
            AddTriangle(a, b, c, color, 0f);
        }

        /// <summary>
        /// 添加一个三角形并设置持续时间。
        /// </summary>
        /// <param name="a">三角形的第一个顶点坐标。</param>
        /// <param name="b">三角形的第二个顶点坐标。</param>
        /// <param name="c">三角形的第三个顶点坐标。</param>
        /// <param name="color">三角形线条颜色。</param>
        /// <param name="life">以秒为单位的持续时间。</param>
        public void AddTriangle(Vector3 a, Vector3 b, Vector3 c, Color color, float life)
        {
            shapeManager.AddTriangle(a, b, c, color, life);
        }

        /// <summary>
        /// 添加一个视锥体，只持续一帧。
        /// </summary>
        /// <param name="frustum">要绘制的视锥体。</param>
        /// <param name="color">视锥体的线条颜色。</param>
        public void AddBoundingFrustum(BoundingFrustum frustum, Color color)
        {
            AddBoundingFrustum(frustum, color, 0f);
        }

        /// <summary>
        /// 添加一个视锥体并设置持续时间。
        /// </summary>
        /// <param name="frustum">要绘制的视锥体。</param>
        /// <param name="color">视锥体的线条颜色。</param>
        /// <param name="life">以秒为单位的持续时间。</param>
        public void AddBoundingFrustum(BoundingFrustum frustum, Color color, float life)
        {
            shapeManager.AddBoundingFrustum(frustum, color, life);
        }

        /// <summary>
        /// 添加一个包围盒，只绘制一帧。
        /// </summary>
        /// <param name="box">要绘制的包围盒。</param>
        /// <param name="color">包围盒的线条颜色。</param>
        public void AddBoundingBox(BoundingBox box, Color color)
        {
            AddBoundingBox(box, color, 0f);
        }

        /// <summary>
        /// 添加一个包围盒并设置持续时间。
        /// </summary>
        /// <param name="box">要绘制的包围盒。</param>
        /// <param name="color">包围盒的线条颜色。</param>
        /// <param name="life">以秒为单位的持续时间。</param>
        public void AddBoundingBox(BoundingBox box, Color color, float life)
        {
            shapeManager.AddBoundingBox(box, color, life);
        }

        /// <summary>
        /// 添加一个包围球，只绘制一帧。
        /// </summary>
        /// <param name="sphere">要绘制的包围球。</param>
        /// <param name="color">包围球的线条颜色。</param>
        public void AddBoundingSphere(BoundingSphere sphere, Color color)
        {
            AddBoundingSphere(sphere, color, 0f);
        }

        /// <summary>
        /// 添加一个包围球并设置持续时间。
        /// </summary>
        /// <param name="sphere">要绘制的包围球。</param>
        /// <param name="color">包围球的线条颜色。</param>
        /// <param name="life">以秒为单位的持续时间。</param>
        public void AddBoundingSphere(BoundingSphere sphere, Color color, float life)
        {
            shapeManager.AddBoundingSphere(sphere, color, life);
        }
        

        public void AddPostEffect(string postEffect)
        {
            ppEffectsList.Add(postEffect);
            postProcessEnabled = true;
        }

        public void RemovePostEffect(string postEffect)
        {
            ppEffectsList.Remove(postEffect);
            if (ppEffectsList.Count <= 0)
                postProcessEnabled = false;
        }

        public void ClearPostEffect()
        {
            ppEffectsList.Clear();
            postProcessEnabled = false;

        }

        #endregion

        #region 私有方法

        /// <summary>
        /// 绘制反射贴图
        /// </summary>
        /// <param name="gameTime"></param>
        private void DrawReflectionMap(GameTime gameTime, CameraSceneNode camera, Matrix ProjectionMatrix, Vector3 CameraPosition)
        {
            // 计算反射相机的属性
            Vector3 reflectedCameraPosition = CameraPosition;
            reflectedCameraPosition.Y = -reflectedCameraPosition.Y + WaterHeight * 2;

            Vector3 reflectedCameraTarget = camera.Target;
            reflectedCameraTarget.Y = -reflectedCameraTarget.Y + WaterHeight * 2;

            //叉乘镜像相机的向前向量和向右向量，就获取了镜像相机的向上向量
            Vector3 cameraRight = Vector3.Transform(Vector3.Right, camera.Pose.Rotation);
            Vector3 invUpVector = Vector3.Cross(cameraRight, reflectedCameraTarget - reflectedCameraPosition);

            //创建镜像反射相机视矩阵
            reflectionViewMatrix = Matrix.CreateLookAt(reflectedCameraPosition, reflectedCameraTarget, invUpVector);

            // 创建剪裁平面
            Vector4 clipPlane = new Vector4(0, 1, 0, -WaterHeight);

            // 设置渲染目标
            graphicsDevice.SetRenderTarget(ReflectionRenderTarget);
            graphicsDevice.Clear(Color .Black );

            for (int i = 0; i < renderList.Count; i++)
            {
                Renderable3DSceneNode rsn = (Renderable3DSceneNode)nodes[renderList[i]];
                if (rsn.IsReflected )
                {
                    rsn.SetClipPlane(clipPlane);
                    rsn.Draw(gameTime, reflectionViewMatrix, ProjectionMatrix, reflectedCameraPosition);
                    rsn.SetClipPlane(Vector4.Zero);
                }
            }

            // 将渲染目标重新设置为后备缓冲
            graphicsDevice.SetRenderTarget(null);
        }

        private void DrawRefractionMap(GameTime gameTime, Matrix ViewMatrix, Matrix ProjectionMatrix, Vector3 CameraPosition)
        {
            // 创建剪裁平面，设置为只绘制此平面之下的场景
            Vector4 clipPlane = new Vector4(0, -1, 0, WaterHeight);

            // 将refractionRenderTarget作为当前渲染目标并绘制需要折射的节点
            graphicsDevice.SetRenderTarget(RefractionRenderTarget);
            graphicsDevice.Clear(Color.Black);

             for (int i = 0; i < renderList.Count; i++)
            {
                Renderable3DSceneNode rsn = (Renderable3DSceneNode)nodes[renderList[i]];
                if (rsn.IsRefracted)
                {
                    rsn.SetClipPlane(clipPlane);
                    rsn.Draw(gameTime, ViewMatrix, ProjectionMatrix, CameraPosition);
                    rsn.SetClipPlane(Vector4.Zero);
                }
            }

            // 将渲染目标重新设置为后备缓冲
            graphicsDevice.SetRenderTarget(null);
        }

        /// <summary>
        /// 对scenenodes重新排序。
        /// 当节点的updateorder改变时必须调用这个方法。
        /// </summary>
        internal void ChangeUpdateOrder(SceneNode node)
        {
            nodes.Sort(updateOrderComparer);
        }

        #endregion

        #region 用于scenenodes的IComparer<T>

        private CompareUpdateOrder<SceneNode> updateOrderComparer = new CompareUpdateOrder<SceneNode>();

        /// <summary>
        /// 根据SceneNode的UpdateOrder属性对Scene.Nodes进行排序
        /// </summary>
        private class CompareUpdateOrder<T> : IComparer<T> where T : SceneNode
        {
            public int Compare(T x, T y)
            {
                return x.UpdateOrder - y.UpdateOrder;
            }
        }
        #endregion
        
    }
}